#ifndef _ENGINE_H_
#define _ENGINE_H_

#include "edge_list.h"
#include "edge.h"
#include "point.h"
#include "point_list.h"

/*Functions used to choose which element of Point we want to compare*/
double getPointX(Point * p);
double getPointY(Point * p);

PointList * getPointsFromEdges(EdgeList * edges);

/*Function which finds specyfic points, dependent on direction(-/+), and point element (x/y)*/
PointList * findPoints(EdgeList * edges, int dir, double (*getXY)(Point *p));

/*This functions allow to find specfific points in list*/
PointList * findHighestPoints(EdgeList * edges);
PointList * findLowestPoints(EdgeList * edges);
PointList * findRightBoundaryPoints(EdgeList * edges);
PointList * findLeftBoundaryPoints(EdgeList * edges);

/*This function shows which points cloud has higher the highest point
    0 - means that left cloud has higher point
    1 - means that right cloud has higher point*/
int checkMaxYCloudPos(EdgeList * left, EdgeList * right);

/*The same situation like in HighestPos, but here we tryind to compare the lowest position*/
int checkMinYCloudPos(EdgeList * left, EdgeList * right);

/*Function which return one point, dependent on direction(-/+), and point element (x/y)*/
Point * getOnePoint(PointList * points, int dir, double (*getXY)(Point *p));

/*Functions which returns one, specyfic point*/
Point * findMaxLeftUpPoint(EdgeList * edges);
Point * findMaxLeftDownPoint(EdgeList * edges);
Point * findMaxRightUpPoint(EdgeList * edges);
Point * findMaxRightDownPoint(EdgeList * edges);
Point * findMaxUpLeftPoint(EdgeList * edges);
Point * findMaxUpRightPoint(EdgeList * edges);
Point * findMaxDownLeftPoint(EdgeList * edges);
Point * findMaxDownRightPoint(EdgeList * edges);

/*Function for selecting first point according to clocks movement or oposite movement*/
Point * getClockDirPoint(Edge * list, Point * p, Point * other, Point * stop, int dirX);

/*This functions produce points list with specyfic order(accordingly to clock's direction, or opposite)*/
PointList * getClockDirectionPointsList(EdgeList * edges, Point * start, Point * stop, int dirX, int dirY);

/*Function for creating points list accordingly to clock's direction*/
PointList * getRightClockPointsList(EdgeList * edges, Point * start, Point * stop);

/*Function for creating points list opposite to clock's direction*/
PointList * getLeftClockPointsList(EdgeList * edges, Point * start, Point * stop);

/*Function for search specyfic point - first to start defining points queue*/
Point * getFirstNextPoint(Edge * list, Point * p, Point * other, int dirX, int dirY);

/*Function for selecting next point in specified chain*/
Point * getPoint(Edge * list, Point * p, Point * other, int dirX, int dirY);

/*Function for creating points chain with specified direction - general*/
PointList * getSpecDirectionPointsList(EdgeList * edges, Point * start, Point * stop, int dirX, int dirY);

/*This functions produce points list with specyfic order from one point to another.
    Additionaly we can specify points interval as a result*/
PointList * getRightUpDirectionPointsList(EdgeList * list, Point * start, Point * stop);
PointList * getLeftUpDirectionPointsList(EdgeList * list, Point * start, Point * stop);
PointList * getRightDownDirectionPointsList(EdgeList * list, Point * start, Point * stop);
PointList * getLeftDownDirectionPointsList(EdgeList * list, Point * start, Point * stop);

/*Function checking if two lines have common point
    return 0 if not
    return 1 if yes*/
int haveLinesCommonPoint(Point * p1, Point * p2, Point * r1, Point * r2);

/*Function for checking if some of points in left chain "see" first point in right chain or
oposite(some of points in right see first in left)*/
Edge * checkSequences(PointList * left, PointList * right, EdgeList * all_left, EdgeList * all_right, int shift, int dir, Edge * prev);

/*Function for finding upper or lower edge connecting two point clouds,
also is based on assumption that Point a in returned edge is alwayes belongs to
left cloud, and Point b belongs to right cloud*/
Edge * findConnectionEdge(PointList * left, PointList * right, EdgeList * all_left, EdgeList * all_right, int dir);

/*Function checking if current POINT is visible from PLACE(other point in second cloud)
by checking all intersections line(connecting POINT and PLACE), with all edges from left and right cloud.
Also checking if intersection is contained in current edge
    return 0 if not
    return 1 if yes
Based on edges*/
int isPointVisibleFromPlaceByEdges(Point * point, Point * place, EdgeList * all_left, EdgeList * all_right);

/*Function checking if current POINT is visible from PLACE(other point in second cloud)
by checking all intersections line(connecting POINT and PLACE), with all edges from left and right cloud.
Also checking if intersection is contained in current edge
    return 0 if not
    return 1 if yes
Based on points*/
int isPointVisibleFromPlaceByPoints(Point * point, Point * place, PointList * all_left, PointList * all_right);

/*Function to make linking triangles between two point clouds - we have specified size relation between clouds*/
TriangleList * makeTriangles(PointList * bigger_list, PointList * smaller_list);

/*Function to make linking triangles between two point clouds - general*/
TriangleList * makeConnectionTriangles(PointList * left_visible_points, PointList * right_visible_points);

/*Function for making new convex hull based on upper and lower linking edges and encluded chains of
visible points between two point clouds*/
EdgeList * makeNewConvexHull(PointList * left_visible_points, EdgeList * left,
                             PointList * right_visible_points, EdgeList * right,
                             Edge * top_edge, Edge * bottom_edge);

/*Function for connecting two point clouds*/
TriangleList * mergeTwoTriangulations(EdgeList * left, EdgeList * right);

/*Function to merge all point clouds in general triangulation*/
TriangleList * mergeAllTriangulations(EdgeList ** edge_list, int n);

#endif

